algo ezzz_base
题目描述:欸,这个base怎么有点不一样??
打开附件,
1 2 3 4 dict:{0: 'J', 1: 'K', 2: 'L', 3: 'M', 4: 'N', 5: 'O', 6: 'x', 7: 'y', 8: 'U', 9: 'V', 10: 'z', 11: 'A', 12: 'B', 13: 'C', 14: 'D', 15: 'E', 16: 'F', 17: 'G', 18: 'H', 19: '7', 20: '8', 21: '9', 22: 'P', 23: 'Q', 24: 'I', 25: 'a', 26: 'b', 27: 'c', 28: 'd', 29: 'e', 30: 'f', 31: 'g', 32: 'h', 33: 'i', 34: 'j', 35: 'k', 36: 'l', 37: 'm', 38: 'W', 39: 'X', 40: 'Y', 41: 'Z', 42: '0', 43: '1', 44: '2', 45: '3', 46: '4', 47: '5', 48: '6', 49: 'R', 50: 'S', 51: 'T', 52: 'n', 53: 'o', 54: 'p', 55: 'q', 56: 'r', 57: 's', 58: 't', 59: 'u', 60: 'v', 61: 'w', 62: '+', 63: '/', 64: '='} chipertext: PNO99NC8GX3nHMCgc8KT9x9SQTKxQpUndn9w
通过“=”和64个字符,得知是base64编码的一个换表,
重新换表后输入密文解码得到flag:XAUTCTF{tH3_m@sTer_0F_b4sE}
e咋不是65537???
题目描述:完了,e不是65537,咋办呢?
关于RSA的前置知识,建议食用关于CTF-RSA题目类型解题思路
打开附件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from Crypto.Util.number import *m=bytes_to_long(b'xxxxxx' ) p=getPrime(256 ) q=getPrime(256 ) e=74 n=p*q c=pow (m,e,n) print ("p=" ,p)print ("q=" ,q)print ("c=" ,c)
简单的RSA,但与一般的RSA不同的是e为74。
e=74=2*37,不与phi(n)互素,得使用最大公约数(GCD)来解答,明文m0,密文c,c=m0^e (mod n)
令t = gcd(e,phi(n)),使e = t*e',从而得到gcd(e',phi(n))=1,重新互素。
计算步骤:
计算t = gcd(e,phi(n))
令e' = e/t,求d = (e')^-1 (mod phi(n))
最后计算m = c^d mod n,也就为最终的明文
EXP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import gmpy2from Crypto.Util.number import *def decrypt (p, q, e, c ): n = p * q phi = (p - 1 ) * (q - 1 ) t = gmpy2.gcd(e, phi) d = gmpy2.invert(e // t, phi) m = pow (c, d, n) print (m) msg = gmpy2.iroot(m, t) print (msg) if msg[1 ]: print (long_to_bytes(msg[0 ])) e=74 p= 86053582917386343422567174764040471033234388106968488834872953625339458483149 q= 72031998384560188060716696553519973198388628004850270102102972862328770104493 c= 3319022875033974423964187739917595278427184197383708001806576530909609086508041781233603918453326670975069669017566120311964861589659101428987255146018427 decrypt(p, q, e, c)
Close Enough
题目描述:听说 RSA 非常安全?可是如果两个质数选得“太接近”,结果会怎样呢?
打开附件,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from Crypto.Util.number import getPrime, bytes_to_long, isPrime, inverse//找到大于n的最大素数 def nextprime (n ): n += 1 while not isPrime(n): n += 1 return n flag = "" e = 65537 p = getPrime(512 ) q = nextprime(p + (1 << 20 )) n = p * q phi = (p - 1 ) * (q - 1 ) d = inverse(e, phi) m = bytes_to_long(bytes (flag, 'utf-8' )) c = pow (m, e, n) print ("n =" , n)print ("c =" , c)''' n = 123396213393166669967180741417142386608199293295343396860771048265983027294499309946576382614888097841439905355747919662299668639065387197060901118151079928153661471067906790612624750455011912757452786783406975664690965235505528837643347037179762435944987875469138529309017524600020070268892228090521628748157 c = 96164959972807254618417630680358223130932461911993510788732180904733021127322517962027522173599694137945712716717847174536035583857007099675639087774330478493529755676338936283880541666682835088571888431839407259147158612358623749706985446040831405827991266588402528874606153834653456725906949141238839683080 '''
我们知道了n、c和e,通过nextprime函数和p、q的设定得知q是p+2^20之后的一个大素数,鉴于生成的素数都很大,所以该题中p和q相差不大。
在这里,我们有两种思路:
费马分解 :我们知道了n = p*q后,设:
1 2 3 a = (p+q)/2 b = (q-p)/2 得 n = (a+b)(a-b) = a^2-b^2
本题,p和q接近,可以从ceil(sqrt(n))将n开方后尝试a,直至a^2-n为完全平方数
基于偏移量的暴力搜索(逼近) :
我们知道了q = p +2^20,则n = p*q = p*(p +2^20) = p^2 + 2^20 * p
则p^2 + 2^20 * p - n也就约等于0了,解方程式得p。
知道了p,也就知道了q,之后就是RSA的常规操作了。
所以,我们解密该RSA的核心思路就是通过p^2 + 2^20 * p - n解方程得到p的大概值,从其前后各试多个数,从是不是素数、q_ca = p+2^20大的下一个素数、p*q_ca是不是为n几个方面猜测,循环直至得到找到p和q。通过数学估算+暴力逼近解密RSA。
EXP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from math import isqrtfrom Crypto.Util.number import isPrime, inverse, long_to_bytesn = 123396213393166669967180741417142386608199293295343396860771048265983027294499309946576382614888097841439905355747919662299668639065387197060901118151079928153661471067906790612624750455011912757452786783406975664690965235505528837643347037179762435944987875469138529309017524600020070268892228090521628748157 c = 96164959972807254618417630680358223130932461911993510788732180904733021127322517962027522173599694137945712716717847174536035583857007099675639087774330478493529755676338936283880541666682835088571888431839407259147158612358623749706985446040831405827991266588402528874606153834653456725906949141238839683080 e = 65537 def nextprime (n ): n += 1 while not isPrime(n): n += 1 return x //估算p delta = 1 << 20 p_guess = (isqrt(4 * n + delta * delta) - delta) // 2 //得到大概值后前后数猜测 for diff in range (-50000 , 50000 ): p = p_guess + diff if p <= 1 : continue if not isPrime(p): continue q = nextprime(p + delta) if p * q == n: break else : print ("Failed to find p, q" ) exit() phi = (p - 1 ) * (q - 1 ) d = inverse(e, phi) m = pow (c, d, n) flag = long_to_bytes(m).decode('utf-8' , errors='ignore' ) print ("Flag:" , flag)
rev SignIn
题目描述:来签个到吧! 什么?你想直接得到flag?
下载附件,用IDA打开,看到全是密密麻麻的函数肯定不想看下去了吧
直接Ctrl+F12看所有的字符串,得到flag:XAUTCTF{F|rsT_5t3P_}
Welcome to Reverse World
题目描述:XAUT网络安全小组的新实验室刚刚上线,传说每一个想要进入实验室的人,必须在入口处输入正确的口令。
然而,这个口令被小组的成员编译进了一段神秘程序中。
想要成为实验室的新成员,你必须通过逆向分析,找出正确的通关口令!
程序已经为你准备好,快来试试吧!
下载附件,用IDA打开,查看字符串,很遗憾,你被骗了 T_T
本题有两种解法 :直接用strings看/将十六进制转换
第一种转换 :进入main函数,
v6数组存储的字符串就是加密后的flag,即 xmmword_2080、xmmword_2090、xmmword_20A0。
单击进入,得到小端序的flag十六进制字节:
我们把这些数值反转,再转换为ASCII字符,
得到flag:XAUTCTF{W3c0me_T0_tH3_w0r1d_oF_R3verSe_3nGineErin9!!!}
第二种直接strings命令 :在命令行输入strings welcome_rev,即可得到flag。
你喜欢贝斯吗
题目描述:听说贝斯蛮好听的,一起来听吧!
下载附件。在IDA中打开,
一样的,查看字符串,看到一串奇怪的字符串WEFVVENURntTM2MwbkRfOUhhczNffQ==,
后面有两个=的一定是base64编码,一个=的一般是base32编码,
我们放到解码模块里得到flag:XAUTCTF{S3c0nD_9Has3_}
base_revenge
题目描述:base reunion
IDA中打开,查看main函数,代码逻辑为用base58字母表加密base64表,然后再用解密后的base64表去加密flag,得到密文。
知道了逻辑,只需找到对应的字符串即可,
先用base58标准字母表解密base64加密表(注意,上下两个字符串都是表,base64表为64个字符)得ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
再用解密后的表解密密文得到flag:XAUTCTF{|_|nu5U@L_b@sE}
Eeeeazy
题目描述:can u find me??? 得到的flag用XAUTCTF{}包裹提交
hint:涉及动态调试,可参考IDA使用技巧之动态调试
IDA打开,定位_main函数,打开:
1 2 3 4 5 6 7 __main(); time (&Time); v5 = localtime (&Time); puts ("Can you find me?\n" ); system ("pause" ); return 0 ; }
没啥好看的,继续看可疑函数,找到了_ques函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 v3 = 2147122737 ; v4[0 ] = 140540 ; v4[1 ] = -2008399303 ; v4[2 ] = 141956 ; v4[3 ] = 139457077 ; v4[4 ] = 262023 ; v4[5 ] = -2008923597 ; v4[6 ] = 143749 ; v4[7 ] = 2118271985 ; v4[8 ] = 143868 ; for ( i = 0 ; i <= 4 ; ++i ) { memset (v2, 0 , sizeof (v2)); v8 = 0 ; v7 = 0 ; v0 = v4[2 * i]; LODWORD (v6) = v4[2 * i - 1 ]; HIDWORD (v6) = v0; while ( v6 > 0 ) { v2[v8++] = v6 % 2 ; v6 /= 2LL ; } for ( j = 50 ; j >= 0 ; --j ) { if ( v2[j] ) { if ( v2[j] == 1 ) { putchar (42 ); ++v7; } } else { putchar (32 ); ++v7; } if ( !(v7 % 5 ) ) putchar (32 ); } result = putchar (10 ); } return result; }
很明显是一个加密函数,你可以选择解密这一段代码,逻辑是将v4数组的奇数索引的值作为低位,偶数为高位,一起组成一个64位的整数v6,以二进制位图打印出图形。
1 2 3 4 v4 = [140540 ,-2008399303 ,141956 ,139457077 ,262023 ,-2008923597 ,143749 ,2118271985 ] for i in range (4 ): n = ((v4[i*2 ] & 0xFFFFFFFF ) << 32 ) | (v4[i*2 +1 ] & 0xFFFFFFFF ) print ('' .join(' *' [((n >> (49 -j)) & 1 )] + ' ' *(j%5 ==4 ) for j in range (50 )))
运行看到flag为 HACKIT4FUN :
但本题真正考察IDA的动态调试。
通过看该附件的_main函数汇编代码, ,在0x401773下断点,让我们能在main函数执行完成前暂停程序;
然后,再看_ques函数,先记下_ques开始的位置0x401520,这里汇编语言中pop ebp即为将把基址指针寄存器弹出堆栈,也就是将我们之前所说的 v6 所包含的值剥开来,呈现在命令行里。所以,我们要想在运行时得到位图,就得在pop这儿下断点,即0x401723,方便查看最终的flag。
我们运行程序,来到该界面:
将General registers里0x0401773修改EIP为刚刚我们记下的_ques开始的位置0x0401520,然后点击继续运行,即可得到二进制位图flag XAUTCTF{HACKIT4FUN} :
糖衣炸弹
题目描述:听说每一位新成员都会得到一颗SS-Team定制糖果吗?
真的有那么善良吗?
“不要随便吃糖,有毒咋办?”妈妈说。
hint:U konw Packed Xanadu?(用UPX脱壳)
下载附件,先查查有无加壳,放到Exeinfo里查壳, ,得到有UPX的壳。
于是,我们到upx指定目录下,运行./upx -d candy.exe给其脱壳(关于UPX相关介绍 ),
然后再IDA打开,定位到主函数(这里不是main):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 v7 = __readfsqword(0x28u ); sub_405450 ("Welcome to XAUT simple XOR crackme!" ); sub_405450 ("Enter the secret code to reveal the flag:" ); if ( sub_4050B0 (v6, 64LL , off_4B06D8) ) { v6[sub_401140 (v6, "\r\n" )] = 0 ; if ( (unsigned int )sub_401A90 (v6) ) { *(__m128i *)v5 = _mm_load_si128((const __m128i *)&xmmword_48AA40); *(__m128i *)&v5[9 ] = _mm_load_si128((const __m128i *)&xmmword_48AA50); v0 = sub_4108A0 (26LL ); if ( v0 ) { for ( i = 0LL ; i != 25 ; ++i ) *(_BYTE *)(v0 + i) = v5[i] ^ 0x5A ; *(_BYTE *)(v0 + 25 ) = 0 ; sub_41BFA0 (2 , (unsigned int )"Good job! The flag is:\n%s\n" , v0, (unsigned int )v5, v1, v2, v5[0 ]); sub_410FB0 (v0); } } else { sub_405450 ("Wrong secret. Try reversing the binary!" ); } } if ( v7 != __readfsqword(0x28u ) ) sub_41C070 (); return 0LL ; }
将xmmword_48AA40和xmmword_48AA50里的数据存入v5里,再进行异或操作得到密文,我们要做的是把密文异或回去 明文 ^ key = 密文,即 密文 ^ key = 明文,这里key为0x5A 。
最后的EXP:
1 2 3 4 5 6 7 enc_flag = [2 , 27 , 15 , 14 , 25 , 14 , 28 , 33 , 3 , 106 , 47 , 5 , 61 , 106 , 14 , 5 , 105 , 44 , 51 , 22 , 5 , 47 , 10 , 34 , 39 ] key = 0x5A plain = '' .join(chr (i ^ key) for i in enc_flag) print ("Decrypted flag:" , plain)